package br.usp.ime.origami.foldcut.util;

import java.util.ArrayList;
import java.util.List;

import br.usp.ime.origami.foldcut.structures.winged.WingedEdge;
import br.usp.ime.origami.foldcut.structures.winged.WingedFace;
import br.usp.ime.origami.model.Point;
import br.usp.ime.origami.model.SimplePoint;
import br.usp.ime.origami.primitives.BasicPrimitives;

public class TriangleFolder
{

	public Molecule foldTriangle(WingedFace face)
	{
		if (face.size() != 6)
		{
			throw new IllegalArgumentException();
		}

		List<FixedEdge> fixeds = getFixedEdges(face);
		List<BissectorEdge> bissectors = new ArrayList<BissectorEdge>();
		List<TangentEdge> tangents = new ArrayList<TangentEdge>();

		List<Point> triangle = new ArrayList<Point>();
		List<Point> triangleTangent = new ArrayList<Point>();

		{
			List<WingedEdge> edges = face.inSequence();
			for (int i = 0; i < 6; i++)
			{
				Point common = findCommonPoint(edges.get(i), edges.get((i + 1) % 6));
				if (i % 2 == 0)
				{
					triangleTangent.add(common);
				}
				else
				{
					triangle.add(common);
				}
			}
		}
		double ab = BasicPrimitives.distance(triangle.get(0), triangle.get(1));
		double bc = BasicPrimitives.distance(triangle.get(1), triangle.get(2));
		double ca = BasicPrimitives.distance(triangle.get(2), triangle.get(0));
		double p = ab + bc + ca;

		double x = (triangle.get(0).getX() * bc) + (triangle.get(1).getX() * ca) + (triangle.get(2).getX() * ab);
		x /= p;
		double y = (triangle.get(0).getY() * bc) + (triangle.get(1).getY() * ca) + (triangle.get(2).getY() * ab);
		y /= p;

		Point incenter = new SimplePoint(x, y);

		List<WingedEdge> edges = face.inSequence();
		for (int i = 0; i < 6; i++)
		{
			Point common = findCommonPoint(edges.get(i), edges.get((i + 1) % 6));
			if (i % 2 == 0)
			{
				TangentEdge e = new TangentEdge(incenter, common);
				e.setType(MoleculeEdge.EdgeType.VALLEY);
				e.setInternalFace(face);
				if (!edges.get(i).getCw().equals(face))
				{
					e.setExternalFace(edges.get(i).getCw());
				}
				else
				{
					e.setExternalFace(edges.get(i).getCcw());
				}
				
				tangents.add(e);
			}
			else
			{
				BissectorEdge edge = new BissectorEdge(incenter, common);
				edge.setType(MoleculeEdge.EdgeType.MOUNTAIN);
				bissectors.add(edge);
			}
		}

		return new Molecule(face, fixeds, tangents, bissectors);
	}

	private Point findCommonPoint(WingedEdge e1, WingedEdge e2)
	{
		if (e1.getStart().equals(e2.getStart()))
		{
			return e1.getStart();
		}
		if (e1.getStart().equals(e2.getEnd()))
		{
			return e1.getStart();
		}
		if (e1.getEnd().equals(e2.getStart()))
		{
			return e1.getEnd();
		}
		if (e1.getEnd().equals(e2.getEnd()))
		{
			return e1.getEnd();
		}
		throw new IllegalStateException("nenhum ponto em comum entre as duas arestas!!!");
	}

	private List<FixedEdge> getFixedEdges(WingedFace face)
	{
		List<FixedEdge> fixeds = new ArrayList<FixedEdge>();
		for (WingedEdge edge : face.inSequence())
		{
			FixedEdge fixedEdge = new FixedEdge(edge.getStart(), edge.getEnd());
			if(edge.isCutEdge())
			{
				fixedEdge.setType(MoleculeEdge.EdgeType.MOUNTAIN);
			}
			else
			{
				fixedEdge.setType(MoleculeEdge.EdgeType.VALLEY);
			}
			
			fixeds.add(fixedEdge);
		}
		return fixeds;
	}
}
